package com.crpc.core.channelHandler;

import com.crpc.common.crpcEnum.CrpcExceptionEnums;
import com.crpc.common.crpcEnum.RequestType;
import com.crpc.common.crpcEnum.ResponseType;
import com.crpc.common.exception.CrpcException;
import com.crpc.core.ServiceConfig;
import com.crpc.core.transport.message.CrpcRequest;
import com.crpc.core.transport.message.CrpcResponse;
import com.crpc.core.transport.message.RequestPayLoad;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.Date;

import static com.crpc.core.CrpcBootStrap.SERVICE_LIST;

/**
 * @author wzy
 * @version 1.0
 * @description:
 * @date 2023/9/28 22:32
 */
@Slf4j
public class MethodRequestHandler extends SimpleChannelInboundHandler<CrpcRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, CrpcRequest crpcRequest) throws Exception {
        //获取负载内容
        RequestPayLoad requestPayLoad = crpcRequest.getRequestPayLoad();
        //根据负载内容进行方法调用
        Object object = null;
        if (crpcRequest.getRequestType() != RequestType.HEART_BEAT.getId()) {
            object = callTargetMethod(requestPayLoad);
            log.info("请求：{}，已经完成方法的调用", crpcRequest.getRequestId());
        }
        //封装响应
        CrpcResponse crpcResponse = CrpcResponse.builder()
                .requestId(crpcRequest.getRequestId())
                .serializeType(crpcRequest.getSerializeType())
                .compressType(crpcRequest.getCompressType())
                .timeStamp(new Date().getTime())
                .code((ResponseType.SUCCESS.getCode()))
                .body(object)
                .build();
        //写出响应
        channelHandlerContext.channel().writeAndFlush(crpcResponse);
    }

    private Object callTargetMethod(RequestPayLoad requestPayLoad) {
        String methodName = requestPayLoad.getMethodName();
        String interfaceName = requestPayLoad.getInterfaceName();
        Object[] parametersValue = requestPayLoad.getParametersValue();
        Class<?>[] parametersType = requestPayLoad.getParametersType();
        //寻找匹配的暴露出去的具体的实现
        ServiceConfig<?> serviceConfig = SERVICE_LIST.get(interfaceName);
        Object refImpl = serviceConfig.getRefImpl();
        //通过反射调用方法 获取对象 ,执行invoke
        Object returnValue = null;
        try {
            Class<?> aClass = refImpl.getClass();
            Method method = aClass.getMethod(methodName, parametersType);
            returnValue = method.invoke(refImpl, parametersValue);
        } catch (Exception e) {
            log.error("调用服务{}的{}方法发生了异常", interfaceName, methodName);
            e.printStackTrace();
            throw new CrpcException(CrpcExceptionEnums.REMOTE_CALL_ERROR);
        }
        return returnValue;
    }
}
